﻿// <copyright file="TrackAction.cs" company="Microsoft Corporation">
// Copyright (c) 2009 Microsoft Corporation All Rights Reserved
// </copyright>
// <author>Michael S. Scherotter</author>
// <email>mischero@microsoft.com</email>
// <date>2009-10-17</date>
// <summary>TrackAction class definition</summary>

namespace Microsoft.WebAnalytics.Behaviors
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.ComponentModel.Composition;
    using System.Linq;
    using System.Windows;
    using System.Windows.Interactivity;
    using Microsoft.WebAnalytics;
    using Microsoft.WebAnalytics.Contracts;
    using Microsoft.WebAnalytics.Data;

    /// <summary>
    /// <img src="../media/Microsoft.WebAnalytics.Behaviors.TrackAction.24x24.png"/> 
    /// Action to track a triggered event
    /// </summary>
    public class TrackAction : TriggerAction<FrameworkElement>
    {
        /// <summary>
        /// Initializes a new instance of the TrackAction class
        /// </summary>
        public TrackAction()
        {
            this.CustomProperties = new Collection<PropertyValue>();
        }

        #region Properties

        /// <summary>
        /// Gets or sets a category for this action
        /// </summary>
        public string Category { get; set; }

        /// <summary>
        /// Gets the event name
        /// </summary>
        public string EventName { get; private set; }

        /// <summary>
        /// Gets or sets an integer that you can use to provide numerical data about the user event.
        /// </summary>
        /// <remarks>Default value is 0</remarks>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods", Justification = "This is should match the AnalyticsEvent.Value name."), 
            TypeConverter(typeof(NullableIntTypeConverter))]
        public int? Value { get; set; }

        /// <summary>
        /// Gets custom properties (name/value pairs) for the action
        /// </summary>
        public Collection<PropertyValue> CustomProperties { get; private set; }

        /// <summary>
        /// Gets or sets the event Logging method
        /// </summary>
        [Import("Log")]
        public Action<AnalyticsEvent> Log { get; set; }

        /// <summary>
        /// Gets or sets the custom actions that can be applied to the event
        /// </summary>
#if WINDOWS_PHONE
        [ImportMany(typeof(ITrackHandler), AllowRecomposition = false)]
        public IEnumerable<Lazy<ITrackHandler, TrackerMetadata>> Handlers { get; set; }
#else
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is the correct way to do ImportMany."), 
        ImportMany(typeof(ITrackHandler), AllowRecomposition = false)]
        public IEnumerable<Lazy<ITrackHandler, ITrackerMetadata>> Handlers { get; set; }
#endif
        #endregion

        #region Methods

        /// <summary>
        /// Initialize the imported parts
        /// </summary>
        protected override void OnAttached()
        {
            base.OnAttached();

            CompositionInitializerEx.SatisfyImports(this);

            this.AssignEventName();
        }

        /// <summary>
        /// Invoke the tracking action
        /// </summary>
        /// <param name="parameter">the event arguments</param>
        protected override void Invoke(object parameter)
        {
            var logevent = new AnalyticsEvent()
            {
                Category = this.Category,
                EventArgs = this.CustomProperties,
                Name = this.EventName,
                ObjectName = this.AssociatedObject.Name,
                ObjectType = this.AssociatedObject.GetType().ToString(),
                Value = this.Value
            };

            var trackers = from item in this.Handlers
                           where item.Metadata.ObjectType == this.AssociatedObject.GetType()
                           select item.Value;

            if (trackers.Count() == 0)
            {
                this.Log(logevent);
            }
            else
            {
                foreach (var tracker in trackers)
                {
                    tracker.Track(this.AssociatedObject, logevent, parameter as EventArgs);
                }
            }
        }
        #endregion

        #region Implementation
        /// <summary>
        /// For an Event Trigger, get the name of the event
        /// </summary>
        private void AssignEventName()
        {
            var triggers = Interaction.GetTriggers(this.AssociatedObject);

            string parentEventName;

            // If the trigger is a TimerTrigger, then set the eventName to "Timer"
            parentEventName = (from trigger in triggers
                               where trigger.Actions.Contains(this) && trigger.GetType().Name == "TimerTrigger"
                               select "Timer").FirstOrDefault();

            if (parentEventName == null)
            {
                parentEventName = (from trigger in triggers.OfType<System.Windows.Interactivity.EventTrigger>()
                                   where trigger.Actions.Contains(this)
                                   select trigger.EventName).FirstOrDefault();
            }

            if (parentEventName != null)
            {
                this.EventName = parentEventName;
            }
        }
        #endregion
    }
}